﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Statistics.cs" company="">
//   
// </copyright>
// <summary>
// Load, store and manage the statistics.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

/*
 * Author: Juan Mompean Esteban
 * Created: 17-11-2011
 */

namespace ITU_vs_Zombies.UsersInfo
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics.Contracts;
    using System.IO;
    using System.Linq;

    /// <summary>
    /// Load, store and manage the statistics.
    /// </summary>
    public class Statistics
    {
        #region Constants and Fields

        /// <summary>
        /// The path.
        /// </summary>
        public static readonly string Path = Directory.GetCurrentDirectory() + @"\Content\statistics.txt";

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="Statistics"/> class.
        /// </summary>
        public Statistics()
        {
            this.Scores = new List<UserStats>();
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets HighScores. Return a list with the 10 best Scores (Sorted).
        /// </summary>
        public IEnumerable<UserStats> HighScores
        {
            get
            {
                var tempScores =
                    this.Scores.Select(item => item.Score.Select(score => new { item.Name, Score = score })).SelectMany(
                        (item) => item).OrderByDescending((item) => item.Score);
                foreach (var tempScore in tempScores.Take(10))
                {
                    UserStats tempUser = this.Scores.Find(user => user.Name.Equals(tempScore.Name));
                    yield return
                        new UserStats
                            {
                                Name = tempScore.Name, 
                                Lost = tempUser.Lost, 
                                Score = new List<uint> { tempScore.Score }, 
                                Time = tempUser.Time, 
                                Victories = tempUser.Victories
                            };
                }
            }
        }

        /// <summary>
        /// Gets Scores.
        /// </summary>
        public List<UserStats> Scores { get; private set; }

        #endregion

        #region Public Methods

        /// <summary>
        /// The add lost.
        /// </summary>
        /// <param name="nplayer">
        /// The nplayer.
        /// </param>
        public void AddLost(string nplayer)
        {
            Contract.Requires(this.Scores.Exists(player => player.Name.Equals(nplayer)));
            UserStats userStats = this.Scores.First(score => score.Name.Equals(nplayer));
            userStats.Lost += 1;
            this.Scores.RemoveAll(score => score.Name.Equals(userStats.Name));
            this.Scores.Add(userStats);
        }

        /// <summary>
        /// The add player.
        /// </summary>
        /// <param name="nplayer">
        /// The nplayer.
        /// </param>
        public void AddPlayer(string nplayer)
        {
            Contract.Requires(nplayer != null);
            Contract.Ensures(this.Scores.Exists(player => player.Name.Equals(nplayer)));
            if (this.Scores.Exists(player => player.Name.Equals(nplayer)))
            {
                return;
            }

            this.Scores.Add(
                new UserStats { Name = nplayer, Time = 0, Victories = 0, Lost = 0, Score = new List<uint>() });
        }

        /// <summary>
        /// The add score.
        /// </summary>
        /// <param name="nplayer">
        /// The nplayer.
        /// </param>
        /// <param name="nscore">
        /// The nscore.
        /// </param>
        public void AddScore(string nplayer, uint nscore)
        {
            Contract.Requires(this.Scores.Exists(player => player.Name.Equals(nplayer)));
            Contract.Requires(nscore >= 0);
            this.Scores.First(score => score.Name.Equals(nplayer)).Score.Add(nscore);
        }

        /// <summary>
        /// The add time.
        /// </summary>
        /// <param name="nplayer">
        /// The nplayer.
        /// </param>
        /// <param name="time">
        /// The time.
        /// </param>
        public void AddTime(string nplayer, uint time)
        {
            Contract.Requires(this.Scores.Exists(player => player.Name.Equals(nplayer)));
            Contract.Requires(time >= 0);
            UserStats userStats = this.Scores.First(score => score.Name.Equals(nplayer));
            userStats.Time += time;
            this.Scores.RemoveAll(score => score.Name.Equals(userStats.Name));
            this.Scores.Add(userStats);
        }

        /// <summary>
        /// The add victory.
        /// </summary>
        /// <param name="nplayer">
        /// The nplayer.
        /// </param>
        public void AddVictory(string nplayer)
        {
            Contract.Requires(this.Scores.Exists(player => player.Name.Equals(nplayer)));
            UserStats userStats = this.Scores.First(score => score.Name.Equals(nplayer));
            userStats.Victories += 1;
            this.Scores.RemoveAll(score => score.Name.Equals(userStats.Name));
            this.Scores.Add(userStats);
        }

        /// <summary>
        /// The read file.
        /// </summary>
        public void ReadFile()
        {
            if (!File.Exists(Path))
            {
                return;
            }

            string[] lines = File.ReadAllLines(Path);
            foreach (string line in lines)
            {
                var scoreList = new List<uint>();
                try
                {
                    string[] splitLine = line.Split(':');
                    string name = splitLine[0];
                    uint time = Convert.ToUInt32(splitLine[1]);
                    uint victories = Convert.ToUInt32(splitLine[2]);
                    uint lost = Convert.ToUInt32(splitLine[3]);
                    for (int i = 4; i < splitLine.Count(); i++)
                    {
                        scoreList.Add(Convert.ToUInt32(splitLine[i]));
                    }

                    this.Scores.Add(
                        new UserStats
                            {
                               Name = name, Time = time, Victories = victories, Lost = lost, Score = scoreList 
                            });
                }
                catch
                {
                    // Ignore lines with errors
                }
            }
        }

        /// <summary>
        /// The user.
        /// </summary>
        /// <param name="player">
        /// The player.
        /// </param>
        /// <returns>
        /// The user statistics.
        /// </returns>
        public UserStats User(string player)
        {
            Contract.Requires(this.Scores.Exists(score => score.Name.Equals(player)));
            return this.Scores.First(score => score.Name.Equals(player));
        }

        /// <summary>
        /// The write file.
        /// </summary>
        public void WriteFile()
        {
            var lines = new string[this.Scores.Count];
            for (int i = 0; i < this.Scores.Count; i++)
            {
                lines[i] = this.Scores[i].ToString();
            }

            File.WriteAllLines(Path, lines);
        }

        #endregion
    }
}